package fr.upmc.i3s.upmcontact.content.collectors;

import java.util.LinkedList;
import java.util.List;

import fr.upmc.i3s.upmcontact.Constants;
import fr.upmc.i3s.upmcontact.R;
import fr.upmc.i3s.upmcontact.backend.BackEndBridgeImpl;
import fr.upmc.i3s.upmcontact.callbacks.ICollectAllCallback;
import fr.upmc.i3s.upmcontact.callbacks.IGetDataCallback;
import fr.upmc.i3s.upmcontact.content.containers.CollectedContentManager;
import fr.upmc.i3s.upmcontact.content.containers.IContainer;
import fr.upmc.i3s.upmcontact.tools.FileUtils;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.Handler;
import android.util.Log;

public class CollectorsController {
	
	private static final String TAG = "CollectorsController";
	
	private Activity context;
	
	private UpmcInfosCollector upmcInfosCollector;
	private MerchantsInfosCollector merchantsInfosCollector;
	private StudentLifeInfosCollector studentLifeInfosCollector;
	private FoundObjectsCollector foundObjectsCollector;
	private LostObjectsCollector lostObjectsCollector;
	private ChatMessagesCollector chatMessagesCollector;
	
	private Handler handler;
	private GuardRunner guardRunner;
	private boolean lock;
	
	//////////////////////////////////////////////////////////////////////////
	
	///////////////
	// SINGLETON //
	///////////////
	
	private static volatile CollectorsController INSTANCE;
	
	public static CollectorsController getInstance(Activity context) {
		if(INSTANCE == null) {
			INSTANCE = new CollectorsController(context);
		}
		return INSTANCE;
	}
	
	private CollectorsController(Activity context) {
		this.context = context;
		this.handler = new Handler();
		this.upmcInfosCollector = new UpmcInfosCollector();
		this.merchantsInfosCollector = new MerchantsInfosCollector();
		this.studentLifeInfosCollector = new StudentLifeInfosCollector();
		this.foundObjectsCollector = new FoundObjectsCollector();
		this.lostObjectsCollector = new LostObjectsCollector();
		this.chatMessagesCollector = new ChatMessagesCollector();
	}
	
	//////////////////////////////////////////////////////////////////////////
	
	public boolean collectAtStartIfNeeded(final Activity context, final ICollectAllCallback callback) {
		if(UpdateDatesManager.shouldUpdateGlobal(context)) {
			Log.d(TAG, "collectAtStartIfNeeded=true");
			collectAllCallback = callback;
			// Ask user
			final boolean[] answer = {false};
			new AlertDialog.Builder(context)
			.setTitle(R.string.update)
			.setMessage(context.getString(R.string.auto_update_msg))
			.setIcon(R.drawable.ic_update)
			.setPositiveButton(android.R.string.yes, new OnClickListener() {
				@Override
				public void onClick(DialogInterface arg0, int arg1) {
					// collect in order : lost objects, found objects, upmc, student, merchants
					lock = true;
					lostObjectsCollector.collect(context, getLostObjectsCallback, true, false);
					answer[0] = true;
				}
			})
			.setNegativeButton(android.R.string.no, new OnClickListener() {
				@Override
				public void onClick(DialogInterface arg0, int arg1) {
					answer[0] = false;
				}
			})
			.setCancelable(true).create().show();
			return answer[0];
		} else {
			Log.d(TAG, "collectAtStartIfNeeded=false");
			return false;
		}
	}
	
	public void collectAll(final Activity context, final ICollectAllCallback callback) {
		// collect in order : lost objects, found objects, upmc, student, merchants, chat messages
		lock = true;
		lostObjectsCollector.collect(context, getLostObjectsCallback, true, false);
		guardRunner = new GuardRunner(callback);
		handler.postDelayed(guardRunner, 500);
	}
	
	private class GuardRunner implements Runnable {
		private ICollectAllCallback callback;
		public GuardRunner(ICollectAllCallback callback) {
			this.callback = callback;
		}
		@Override
		public void run() {
			if(lock == false) {
				callback.collectEnded();
			} else {
				handler.postDelayed(guardRunner, 500);
			}
		}
	}
	
	//////////////////////////////////////////////////////////////////////////
	
	  ///////////////
	 // CALLBACKS //
	///////////////
	
	private ICollectAllCallback collectAllCallback = null;
	
	private IGetDataCallback getLostObjectsCallback = new IGetDataCallback() {
		@Override
		public void getDataEndedOk(LinkedList<Object> list) {
			Log.i(TAG, "getLostObjectsCallback.getDataEndedOk.list.size="+list.size());
			CollectedContentManager.getInstance(context).getLostObjects().updateWith(list);
			UpdateDatesManager.storeLostObjectsUpdateDate(context);
			// sort by ascending date
			CollectedContentManager.getInstance(context).getLostObjects().sortBy(IContainer.DESCENDING);
			// save content for offline access :
			CollectedContentManager.getInstance(context).getLostObjects().saveState(context);
			// delete unused local files :
			List<String> exceptedFiles = CollectedContentManager.getInstance(context).getLostObjects().getRequiredExternalFileList();
			FileUtils.rmAllFilesInDirectoryExcept(Constants.LOST_EXTERNAL_FOLDER, exceptedFiles);
			// collect next : found objects :
			foundObjectsCollector.collect(context, getFoundObjectsCallback, true, false);
		}
		@Override
		public void getDataEndedNok() {
			Log.w(TAG, "getLostObjectsCallback.getDataEndedNok");
			// collect next : found objects :
			foundObjectsCollector.collect(context, getFoundObjectsCallback, true, false);
		}
	};
	
	private IGetDataCallback getFoundObjectsCallback = new IGetDataCallback() {
		@Override
		public void getDataEndedOk(LinkedList<Object> list) {
			Log.i(TAG, "getFoundObjectsCallback.getDataEndedOk.list.size="+list.size());
			CollectedContentManager.getInstance(context).getFoundObjects().updateWith(list);
			UpdateDatesManager.storeFoundObjectsUpdateDate(context);
			// sort by ascending date
			CollectedContentManager.getInstance(context).getFoundObjects().sortBy(IContainer.DESCENDING);
			// save content for offline access :
			CollectedContentManager.getInstance(context).getFoundObjects().saveState(context);
			// delete unused local files :
			List<String> exceptedFiles = CollectedContentManager.getInstance(context).getFoundObjects().getRequiredExternalFileList();
			FileUtils.rmAllFilesInDirectoryExcept(Constants.FOUND_EXTERNAL_FOLDER, exceptedFiles);
			// collect next : upmc infos :
			upmcInfosCollector.collect(context, getUpmcInfosCallback, true, false);
		}
		@Override
		public void getDataEndedNok() {
			Log.w(TAG, "getFoundObjectsCallback.getDataEndedNok");
			// collect next : upmc infos :
			upmcInfosCollector.collect(context, getUpmcInfosCallback, true, false);
		}
	};
	
	private IGetDataCallback getUpmcInfosCallback = new IGetDataCallback() {
		@Override
		public void getDataEndedOk(LinkedList<Object> list) {
			Log.i(TAG, "getUpmcInfosCallback.getDataEndedOk.list.size()"+list.size());
			CollectedContentManager.getInstance(context).getUpmcInfos().updateWith(list);
			UpdateDatesManager.storeUpmcInfosUpdateDate(context);
			// sort by ascending date
			CollectedContentManager.getInstance(context).getUpmcInfos().sortBy(IContainer.DESCENDING);
			// save content for offline access :
			CollectedContentManager.getInstance(context).getUpmcInfos().saveState(context);
			// delete unused local files :
			List<String> exceptedFiles = CollectedContentManager.getInstance(context).getUpmcInfos().getRequiredExternalFileList();
			FileUtils.rmAllFilesInDirectoryExcept(Constants.UPMC_EXTERNAL_FOLDER, exceptedFiles);
			// collect next : student life infos :
			studentLifeInfosCollector.collect(context, getStudentLifeInfosCallback, true, false);
		}
		@Override
		public void getDataEndedNok() {
			Log.w(TAG, "getUpmcInfosCallback.getDataEndedNok");
			// collect next : student life infos :
			studentLifeInfosCollector.collect(context, getStudentLifeInfosCallback, true, false);
		}
	};
	
	private IGetDataCallback getStudentLifeInfosCallback = new IGetDataCallback() {
		@Override
		public void getDataEndedOk(LinkedList<Object> list) {
			Log.i(TAG, "getStudentLifeInfosCallback.getDataEndedOk.list.size="+list.size());
			CollectedContentManager.getInstance(context).getStudentLifeInfos().updateWith(list);
			UpdateDatesManager.storeStudentLifeInfosUpdateDate(context);
			// sort by ascending date
			CollectedContentManager.getInstance(context).getStudentLifeInfos().sortBy(IContainer.DESCENDING);
			// save content for offline access :
			CollectedContentManager.getInstance(context).getStudentLifeInfos().saveState(context);
			// delete unused local files :
			List<String> exceptedFiles = CollectedContentManager.getInstance(context).getStudentLifeInfos().getRequiredExternalFileList();
			FileUtils.rmAllFilesInDirectoryExcept(Constants.STUDENT_EXTERNAL_FOLDER, exceptedFiles);
			// collect next : merchants infos :
			merchantsInfosCollector.collect(context, getMerchantInfosCallback, true, false);
		}
		@Override
		public void getDataEndedNok() {
			Log.w(TAG, "getStudentLifeInfosCallback.getDataEndedNok");
			// collect next : merchants infos :
			merchantsInfosCollector.collect(context, getMerchantInfosCallback, true, false);
		}
	};
	
	private IGetDataCallback getMerchantInfosCallback = new IGetDataCallback() {
		@Override
		public void getDataEndedOk(LinkedList<Object> list) {
			Log.i(TAG, "getMerchantInfosCallback.getDataEndedOk.list.size="+list.size());
			CollectedContentManager.getInstance(context).getMerchantsInfos().updateWith(list);
			UpdateDatesManager.storeMerchantsInfosUpdateDate(context);
			// sort by ascending date
			CollectedContentManager.getInstance(context).getMerchantsInfos().sortBy(IContainer.DESCENDING);
			// save content for offline access :
			CollectedContentManager.getInstance(context).getMerchantsInfos().saveState(context);
			// delete unused local files :
			List<String> exceptedFiles = CollectedContentManager.getInstance(context).getMerchantsInfos().getRequiredExternalFileList();
			FileUtils.rmAllFilesInDirectoryExcept(Constants.MERCHANTS_EXTERNAL_FOLDER, exceptedFiles);
			// collect next : chat messages :
			chatMessagesCollector.collect(context, getChatMessagesCallback, true, true);
		}
		@Override
		public void getDataEndedNok() {
			Log.w(TAG, "getMerchantInfosCallback.getDataEndedNok");
			// collect next : merchants infos :
			chatMessagesCollector.collect(context, getChatMessagesCallback, true, true);
		}
	};
	
	private IGetDataCallback getChatMessagesCallback = new IGetDataCallback() {
		@Override
		public void getDataEndedOk(LinkedList<Object> list) {
			Log.i(TAG, "getChatMessagesCallback.getDataEndedOk.list.size="+list.size());
			CollectedContentManager.getInstance(context).getChatMessages().updateWith(list);
			UpdateDatesManager.storeChatMessagesUpdateDate(context);
			// sort by ascending date
			CollectedContentManager.getInstance(context).getChatMessages().sortBy(IContainer.ASCENDING);
			// save content for offline access :
			CollectedContentManager.getInstance(context).getChatMessages().saveState(context);
			// delete unused local files :
			List<String> exceptedFiles = CollectedContentManager.getInstance(context).getChatMessages().getRequiredExternalFileList();
			FileUtils.rmAllFilesInDirectoryExcept(Constants.CHAT_MESSAGES_EXTERNAL_FOLDER, exceptedFiles);
			// end of collect, store global updated date :
			UpdateDatesManager.storeGlobalUpdateDate(context);
			if(collectAllCallback != null) {
				collectAllCallback.collectEnded();
			}
			setCancelLoadingDialogForAWhile(false);
			lock = false;
		}
		@Override
		public void getDataEndedNok() {
			Log.w(TAG, "getChatMessagesCallback.getDataEndedNok");
			// end of collect, store global updated date :
			UpdateDatesManager.storeGlobalUpdateDate(context);
			if(collectAllCallback != null) {
				collectAllCallback.collectEnded();
			}
			setCancelLoadingDialogForAWhile(false);
			lock = false;
		}
	};
	

	//////////////////////////////////////////////////////////////////////////
	
	public UpmcInfosCollector getUpmcInfosCollector() {
		return upmcInfosCollector;
	}

	public MerchantsInfosCollector getMerchantsInfosCollector() {
		return merchantsInfosCollector;
	}

	public StudentLifeInfosCollector getStudentLifeInfosCollector() {
		return studentLifeInfosCollector;
	}

	public FoundObjectsCollector getFoundObjectsCollector() {
		return foundObjectsCollector;
	}

	public LostObjectsCollector getLostObjectsCollector() {
		return lostObjectsCollector;
	}
	
	public ChatMessagesCollector getChatMessagesCollector() {
		return chatMessagesCollector;
	}
	
	
	//////////////////////////////////////////////////////////////////////////
	
	public void setCancelLoadingDialogForAWhile(boolean value) {
		BackEndBridgeImpl.getInstance(context).setCancelForAWhile(value);
	}
	
}
